package tech.yixiyun.framework.kuafu.kits;


import cn.hutool.core.util.StrUtil;
import tech.yixiyun.framework.kuafu.controller.request.param.ParamType;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Boolone
 * @date 2020/1/5
 */
public class StringKit extends StrUtil {

    /**
     * 正则表达式编译的Pattern，防止同一个表达式多次编译浪费时间
     */
    private static final ConcurrentHashMap<String, Pattern> PATTERN_LIB = new ConcurrentHashMap<>();

    /**
     * 根据正则表达式返回第一个匹配的字符串，<b>该方法会将表达式缓存</b>，方便以后重复使用。
     * 所以如果项目中会用到大量不同表达式的时候，要注意内存占用情况
     * @param sourceStr 源字符串
     * @param patternStr 正则匹配表达式
     * @return
     */
    public static String matchFirst(String sourceStr, String patternStr) {
        if (isBlank(sourceStr) || isBlank(patternStr)) {
            return null;
        }
        Pattern pattern = PATTERN_LIB.get(patternStr);
        if (pattern == null) {
            pattern = Pattern.compile(patternStr);
            PATTERN_LIB.putIfAbsent(patternStr, pattern);
        }
        Matcher matcher = pattern.matcher(sourceStr);
        if (matcher.find()) {
            return matcher.group();
        }
        return null;
    }

    /**
     * 根据正则表达式返回匹配的字符串，<b>该方法会将表达式缓存</b>，方便以后重复使用。
     * 所以如果项目中会用到大量不同表达式的时候，要注意内存占用情况
     * @param sourceStr 源字符串
     * @param patternStr 正则匹配表达式
     * @return
     */
    public static String[] matchAll(String sourceStr, String patternStr) {
        if (isBlank(sourceStr) || isBlank(patternStr)) {
            return null;
        }
        Pattern pattern = PATTERN_LIB.get(patternStr);
        if (pattern == null) {
            pattern = Pattern.compile(patternStr);
            PATTERN_LIB.putIfAbsent(patternStr, pattern);
        }
        Matcher matcher = pattern.matcher(sourceStr);
        List<String> results = new ArrayList<>();
        while (matcher.find()) {
            results.add(matcher.group());
        }
        return results.toArray(new String[0]);
    }

    /**
     * 将字符串用,分割，然后转换成对应类型的数组
     * @param str
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> Object splitToArray(String str, Class<T> clazz) {
        if (str == null) return null;
        String[] strs = str.split(",");
        if (clazz == String.class) {
            return (T[]) strs;
        }
        Object array =  Array.newInstance(clazz, strs.length);
        for (int i = 0; i < strs.length; i++) {
            String s = strs[i];
            Array.set(array, i, convert(s, clazz));
        }
        return array;
    }



    /**
     * 将字符串转化成对应类型，<b>注意：<b/>,该方法只能用来转换基本类型及包装类、时间日期类型、BigDecimal 以及 BigInteger。
     * @param str
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T convert(String str, Class<T> clazz) {
        if (clazz == String.class) {
            return (T) str;
        }

        if (isBlank(str)) {
            return (T) ParamType.getDefaultValue(clazz);
        }

        if (clazz == int.class || clazz == Integer.class) {
            return (T) Integer.valueOf(Double.valueOf(str).intValue());
        }
        if (clazz == double.class || clazz == Double.class) {
            return (T) Double.valueOf(str);
        }
        if (clazz == boolean.class || clazz == Boolean.class) {
            if (str.equals("true".intern()) || str.equals("on".intern()) || str.equals("1".intern())) {
                return (T) Boolean.TRUE;
            }
            return (T) Boolean.FALSE;
        }
        if (clazz == long.class || clazz == Long.class) {
            return (T) Long.valueOf(new BigDecimal(str).longValue());
        }
        if (clazz == Date.class ) {
            return (T) DateKit.parseDate(str);
        }
        if (clazz == java.sql.Date.class) {
            Date date = DateKit.parseDate(str);
            return date == null ? null : (T) new java.sql.Date(date.getTime());
        }

        if (clazz == Time.class) {
            Date date = DateKit.parseDate(str);
            return date == null ? null : (T) new Time(date.getTime());
        }
        if (clazz == short.class || clazz == Short.class) {
            return (T) Short.valueOf(new BigDecimal(str).shortValue());
        }
        if (clazz == byte.class || clazz == Byte.class) {
            return (T) Byte.valueOf(new BigDecimal(str).byteValue());
        }
        if (clazz == float.class || clazz == Float.class) {
            return (T) Float.valueOf(new BigDecimal(str).floatValue());
        }
        if (clazz == char.class || clazz == Character.class) {
            return (T) new Character(str.charAt(0));
        }

        if (clazz.isEnum()) {
            try {
                Method getValueOf = clazz.getDeclaredMethod("valueOf", String.class);
                return (T) getValueOf.invoke(clazz, str);
            } catch (Exception e) {
                return null;
            }
        }


//        if (clazz == LocalDate.class) {
//            return (T) DateUtils.parseDate(str);
//        }
//        if (clazz == LocalTime.class) {
//            return (T) DateUtils.parseTime(str);
//        }
//
//        if (clazz == LocalDateTime.class) {
//            return (T) DateUtils.parseDateTime(str);
//        }

        if (clazz == BigInteger.class) {
            return (T) new BigInteger(str);
        }

        if (clazz == BigDecimal.class) {
            return (T) new BigDecimal(str);
        }
        throw new ClassCastException(str + "不支持直接转化为" + clazz.getSimpleName() + "类型数据");
    }




    /**
     * 如果原字符串是null，就返回一个新的字符串，否则返回原字符串自己
     * @param originStr 原字符串
     * @param newStr 新字符串
     * @return
     */
    public static String nullOr(String originStr, String newStr) {
        return originStr == null ? newStr : originStr;
    }

    /**
     * 如果原字符串是null或者空字符串，就返回一个新的字符串，否则返回原字符串自己
     * @param originStr 原字符串
     * @param newStr 新字符串
     * @return
     */
    public static String emptyOr(String originStr, String newStr) {
        return isBlank(originStr)  ? newStr : originStr;
    }

    public static String replaceOnce(String text, String searchString, String replacement) {
        return replace(text, searchString, replacement, 1, false);
    }

    private static String replace(String text, String searchString, String replacement, int max, boolean ignoreCase) {
        if (!isEmpty(text) && !isEmpty(searchString) && replacement != null && max != 0) {
            if (ignoreCase) {
                searchString = searchString.toLowerCase();
            }

            int start = 0;
            int end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start, false);
            if (end == -1) {
                return text;
            } else {
                int replLength = searchString.length();
                int increase = replacement.length() - replLength;
                increase = increase < 0 ? 0 : increase;
                increase *= max < 0 ? 16 : (max > 64 ? 64 : max);

                StringBuilder buf;
                for(buf = new StringBuilder(text.length() + increase); end != -1; end = ignoreCase ? indexOfIgnoreCase(text, searchString, start) : indexOf(text, searchString, start, false)) {
                    buf.append(text, start, end).append(replacement);
                    start = end + replLength;
                    --max;
                    if (max == 0) {
                        break;
                    }
                }

                buf.append(text, start, text.length());
                return buf.toString();
            }
        } else {
            return text;
        }
    }

}
